package com.dl.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dl.cache.RedisCacheSessionDao;
import com.dl.pojo.User;
import com.dl.service.UserService;
import com.dl.utils.ConstantField;
import com.dl.utils.EmailUtils;
import com.dl.utils.ShiroUtils;
import com.dl.utils.VerifyCodeUtils;
import io.swagger.annotations.*;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author DL
 * @create 2021-5-7 16:39:25
 */
@Api(tags="登录修改操作接口")
@Controller
@Log4j2
public class LoginController {

    @Resource
    private UserService userService;

    @Resource
    private EmailUtils emailUtils; //邮件发送工具类

    @ApiOperation("登录页")
    @GetMapping({"/","/login"})
    public String toLogin(){
        return "login";
    }

    @ApiOperation(value="未授权",notes="未授权页面")
    @GetMapping ("/unauthorized")
    public String unauthorized(){
        return "error/unauthorized";
    }

    @ApiOperation(value="验证码",notes="获得登录验证码")
    @GetMapping ("/captcha")
    public void verify(HttpSession session,HttpServletResponse response) throws IOException {
        //设置验证码位数
        String captcha = VerifyCodeUtils.generateVerifyCode(4);
        //验证码放入session
        session.setAttribute("sessionCaptcha", captcha);
        //获得输出流
        ServletOutputStream os = response.getOutputStream();
        //设置响应头
        response.setContentType("application/octet-stream");
        //获得验证码图片
        VerifyCodeUtils.outputImage(150,60, os, captcha);
        os.flush();
        os.close();
    }

    @RequiresAuthentication
    @ApiOperation(value="清空授权缓存",notes="清空授权缓存，下一次查询数据库")
    @ResponseBody
    @GetMapping("/clearAuthorizationCache")
    public boolean clearAuthorizationCache() {
        return ShiroUtils.clearAuthorizationCache();
    }

    @RequiresAuthentication
    @ApiOperation(value="清空认证缓存",notes="清空认证缓存，下一次查询数据库")
    @ResponseBody
    @GetMapping("/clearAuthenticationCache")
    public boolean clearAuthenticationCache() {
        return ShiroUtils.clearAuthenticationCache();
    }

    @ApiOperation(value="登录",notes="参数为用户名和密码")
/*    @ApiImplicitParams({
            @ApiImplicitParam(name="username",value="用户名",required=true,paramType="form"),
            @ApiImplicitParam(name="password",value="密码",required=true,paramType="form"),
    })*/
    @PostMapping("/login")
    public String login(HttpSession session, RedirectAttributes redirectAttributes,
                        String username, String password, String captcha, @RequestParam(defaultValue = "0") String rememberMe){

        String sessionCaptcha = (String) session.getAttribute("sessionCaptcha");

        log.debug("sessionCaptcha:{}", sessionCaptcha);
        log.debug("captcha:{}", captcha);
        //将字符串与指定的对象比较，不考虑大小写
        if ("admin".equals(username) || sessionCaptcha.equalsIgnoreCase(captcha)){
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装登录用户数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                if (rememberMe.equals("1")){//判断是否开启记住我功能
                    System.out.println("rememberME");
                    token.setRememberMe(true);
                }
                //交由shiro执行登录，如果没有抛出异常则成功
                subject.login(token);
                System.out.println("======================login之后=====================");

                if (subject.hasRole("admin")) {
                    return "redirect:user/userInfo";
                }else{
                    return "redirect:student/info";
                }

            }catch (LockedAccountException e){
                log.info("账号锁定:{}", username);
                redirectAttributes.addFlashAttribute("msg",e.getMessage());
                return "redirect:login";
            }catch (UnknownAccountException e){
                log.info("登录异常:{}", username);
                redirectAttributes.addFlashAttribute("msg","用户名错误");
                return "redirect:login";
            }catch (IncorrectCredentialsException e){
                log.info("密码错误:{}", username);
                redirectAttributes.addFlashAttribute("msg","密码错误");
                return "redirect:login";
            }catch (ExcessiveAttemptsException e){
                log.info("错误次数过多:{}", username);
                redirectAttributes.addFlashAttribute("msg",e.getMessage());
                return "redirect:login";
            }
        }else {
            redirectAttributes.addFlashAttribute("msg","验证码错误");
            return "redirect:login";
        }
    }

    @ApiOperation(value="修改密码",notes="参数为原密码，新密码和确认新密码")
/*    @ApiImplicitParams({
            @ApiImplicitParam(name="originalPsd",value="原密码",required=true,paramType="form"),
            @ApiImplicitParam(name="newPsd",value="新密码",required=true,paramType="form"),
            @ApiImplicitParam(name="confirmNewPsd",value="确认新密码",required=true,paramType="form"),
    })*/
    @PostMapping("/modify")
    @ResponseBody
    public HashMap<String, String> modify(String originalPsd, String newPsd, String confirmNewPsd){
        System.out.println("originalPsd = " + originalPsd);
        System.out.println("newPsd = " + newPsd);
        System.out.println("confirmNewPsd = " + confirmNewPsd);

        HashMap<String, String> map = userService.modify(originalPsd, newPsd, confirmNewPsd);
        System.out.println("map = " + map);
        return map;
    }

    @ApiOperation(value="前往注册",notes="注册页面")
    @GetMapping ("/register")
    public String toRegister(){
        return "register";
    }

    @ApiOperation(value="注册",notes="用户注册")
    @PostMapping("/register")
    @ResponseBody
    public HashMap<String, String> register(User user){
        HashMap<String, String> map = new HashMap<>();
        try {
            String originalPwd = user.getPassword();//保存未加密前的密码给用户
            boolean register = userService.register(user);
            if (register) {
                map.put("msg","注册成功，快去登录看看吧~");
                sendEmail("慧学习",user.getEmail(),user.getUsername(),originalPwd);
            }else{
                map.put("msg","注册失败-数据库写入异常");
            }
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg","注册失败");
        }
        return map;
    }

    @ApiOperation(value="校验注册信息",notes="校验用户注册信息，判断用户名是否重复")
    @ResponseBody
    @PostMapping("/check")
    public boolean check(@RequestBody String username){
        //解析json
        JSONObject jsonObject = JSON.parseObject(username);
        String usernameStr = (String) jsonObject.get("username");
        //判断用户名是否重复
        return userService.queryUserByName(usernameStr) == null;
    }

    @ApiOperation(value="退出",notes="退出登录，移除session")
    @GetMapping ("/logout")
    public String loginOut(HttpSession session){
        //session.removeAttribute(ConstantField.LOGIN_INFO);
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:login";
    }

    /**
     * 发送注册信息邮件，异步执行
     */
    @Async
    public void sendEmail(String subject, String emailTO, String username, String password){
        try {
            emailUtils.sendMail(subject,emailTO,username,password);
        } catch (MessagingException e) {
            e.printStackTrace();
        }

    }
}
